package com.fp.m7.server.services;

import gwtupload.server.UploadAction;
import gwtupload.server.exceptions.UploadActionException;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.annotation.Secured;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.fp.m7.api.model.Account;
import com.fp.m7.server.auth.AuthenticationChecker;
import com.fp.m7.server.util.ImageUtils;

/**
 * Handles uploading user avatars and putting them in appropriate system folders.
 * 
 * @author 7
 */
public class UploadServlet extends UploadAction {
    private static final long serialVersionUID = 9076825124288274237L;

    @Value("#{appSettings['upload.savePath']}")
    private String savePath;

    @Value("#{appSettings['upload.conversionFormat']}")
    private String conversionFormat;

    @Value("#{appSettings['upload.defaultFilename']}")
    private String defaultFilename;

    @Value("#{appSettings['upload.urlPrefix']}")
    private String urlPrefix;

    @Autowired
    private AccountServiceImpl accountService;

    @Autowired
    private AuthenticationChecker authChecker;

    public UploadServlet() {
        logger.info("Upload Servlet initializing...");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // a workaround for forcing this servlet to autowire its components
        WebApplicationContext webAppCtx = WebApplicationContextUtils
                .getRequiredWebApplicationContext(getServletContext());
        webAppCtx.getAutowireCapableBeanFactory().autowireBean(this);

        logger.info("Upload Servlet initialized.");
    }

    /**
     * Override executeAction to save the received files in a custom place and delete this items from session.
     */
    @Override
    @Transactional(readOnly = false)
    @Secured("ROLE_USER")
    public String executeAction(HttpServletRequest request, List<FileItem> sessionFiles) throws UploadActionException {
        String response = "";
        try {
            Account authAccount = authChecker.getLoggedAccount();

            for (FileItem item : sessionFiles) {
                if (!item.isFormField()) {

                    String accountDirectory = String.valueOf(authAccount.getId().hashCode()); // hash code of account id

                    StringBuilder builder = new StringBuilder(savePath).append(accountDirectory);

                    File file = new File(builder.toString()); // system path to this account's base directory
                    file.mkdirs(); // make sure the directories will be created (if they don't exist)

                    builder.append(File.separator).append(defaultFilename); // full disk path to the avatar image file
                    file = new File(builder.toString());

                    BufferedImage img = ImageIO.read(item.getInputStream()); // read the original image
                    BufferedImage scaled = ImageUtils.resizeImage(img, 100, 100); // scale it down to 100x100px
                    ImageIO.write(scaled, conversionFormat, file); // save to system file

                    // now take care of updating the account avatar url to point to newly created
                    builder = new StringBuilder(urlPrefix).append(accountDirectory).append("/").append(defaultFilename);
                    accountService.updateAvatarUrl(builder.toString());

                    // Send a customized message to the client.
                    response = "File saved successfully";
                }

            }
        } catch (Exception e) {
            throw new UploadActionException(e);
        }

        // Remove files from session because we have a copy of them
        removeSessionFileItems(request);

        // Send your customized message to the client.
        return response;
    }

    /**
     * Get the content of an uploaded file.
     */
    @Override
    public void getUploadedFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String accountHash = request.getParameter("account");

        String fullPath = new StringBuilder(savePath)//
                .append(accountHash)//
                .append(File.separator)//
                .append(defaultFilename).toString();

        File file = new File(fullPath);
        if (file.isFile()) {
            response.setContentType("image/jpeg");
            FileInputStream is = new FileInputStream(file);
            copyFromInputStreamToOutputStream(is, response.getOutputStream());
            is.close();
        } else {
            renderXmlResponse(request, response, "ERROR_ITEM_NOT_FOUND");
        }
    }

    public void setAuthChecker(AuthenticationChecker authChecker) {
        this.authChecker = authChecker;
    }

    public void setAccountService(AccountServiceImpl accountService) {
        this.accountService = accountService;
    }

    public void setSavePath(String savePath) {
        this.savePath = savePath;
    }

    public void setConversionFormat(String conversionFormat) {
        this.conversionFormat = conversionFormat;
    }

    public void setDefaultFilename(String defaultFilename) {
        this.defaultFilename = defaultFilename;
    }

    public void setUrlPrefix(String urlPrefix) {
        this.urlPrefix = urlPrefix;
    }
}